//John
using System;
using System.Threading.Tasks;
using System.Threading;
using System.Collections.Generic;

namespace JohnSpace
{
	public class John_Programme
	{
		/// <summary>
		/// John矩阵乘法
		/// Truffer依据John代码修改
		/// </summary>
		/// <param name="a1_r">矩阵A Row Number</param>
		/// <param name="a1_c">矩阵A Volumn Number</param>
		/// <param name="a2_r">矩阵B Row Number</param>
		/// <param name="a2_c">矩阵B Column Number</param>
		/// <param name="matrix_a">矩阵A数据</param>
		/// <param name="matrix_b">矩阵B数据</param>
		/// <param name="a3_r">矩阵C Row Number</param>
		/// <param name="a3_c">矩阵C Column Number</param>
		/// <param name="probe_row">测点row</param>
		/// <param name="probe_col">测点column</param>
		/// <param name="t1024">测点C[probe_row,probe_col]数据</param>
		/// <returns>返回计算时间（毫秒）</returns>
		public static double Execute(int a1_r, int a1_c, int a2_r, int a2_c, double[,] matrix_a, double[,] matrix_b, out int a3_r, out int a3_c, int probe_row, int probe_col, out double t1024)
		{
			Random rnd = new Random();
			try
			{
				double[] arr1 = new double[a1_r * a1_c];
				for (int i = 0; i < a1_r; i++)
				{
					for (int j = 0; j < a1_c; j++)
					{
						arr1[i * a1_c + j] = matrix_a[i, j];
					}
				}
				CMatrix m1 = new CMatrix(a1_r, a1_c, arr1);
				double[] arr2 = new double[a2_r * a2_c];
				for (int i = 0; i < a2_r; i++)
				{
					for (int j = 0; j < a2_c; j++)
					{
						arr2[i * a2_c + j] = matrix_b[i, j];
					}
				}
				CMatrix m2 = new CMatrix(a2_r, a2_c, arr2);

				DateTime beforDT = System.DateTime.Now;
				CMatrix m3 = m1.multi(m2);
				DateTime afterDT = System.DateTime.Now;
				TimeSpan ts = afterDT.Subtract(beforDT);

				a3_r = m3.RowCnt;
				a3_c = m3.ColCnt;
				t1024 = m3.getEle(probe_row * a3_c + probe_col + 1); // 减1！

				return ts.TotalMilliseconds;
			}
			catch (Exception ex)
			{
				throw new Exception("John's Programme Error:" + ex.Message);
			}
		}
		/*
		/// <summary>
		/// The entry point of the program, where the program control starts and ends. 测试库驱动函数
		/// </summary>
		/// <param name="args">The command-line arguments.</param>
		public static void Main(string[] args)
		{
			try
			{
				int a1_r = 2049, a1_c = 2048, a2_r = 2048, a2_c = 2047;
				double[] arr1 = new double[a1_r * a1_c];
				for (int i = 0; i < a1_r * a1_c; i++)
				{
					arr1[i] = 1.0;
				}
				CMatrix m1 = new CMatrix(a1_r, a1_c, arr1);
				double[] arr2 = new double[a2_r * a2_c];
				for (int i = 0; i < a2_r * a2_c; i++)
				{
					arr2[i] = 1.0;
				}
				CMatrix m2 = new CMatrix(a2_r, a2_c, arr2);
				CMatrix m3 = m1.multi(m2);
			}
			catch (Exception e)
			{
				Console.WriteLine(e.Message);
			}

			Console.ReadKey();
		}
		*/
	}

	/// <summary>
	/// CVector. 向量索引从1开始
	/// </summary>
	public class CVector
	{
		/// <summary>
		/// Initializes a new instance of the <see cref="T:CalcMatrix.CVector"/> class. 传入元素个数及所有元素数组
		/// </summary>
		/// <param name="eleCnt">Ele count.</param>
		/// <param name="arr">Arr.</param>
		public CVector(int eleCnt, double[] arr)
		{
			EleCnt = eleCnt;
			this.arr = arr;
		}

		/// <summary>
		/// Multi the specified r. 向量点乘
		/// </summary>
		/// <param name="r">The red component.</param>
		public CVector multi(CVector r)
		{
			CVector ret = new CVector(EleCnt, new double[EleCnt]);
			for (int i = 1; i <= EleCnt; i++)
			{
				ret.setEle(i, getEle(i) * r.getEle(i));
			}

			return ret;
		}

		/// <summary>
		/// Sum this instance. 向量所有元素和
		/// </summary>
		public double sum()
		{
			double ret = 0.0;
			for (int i = 1; i <= EleCnt; i++)
			{
				ret += getEle(i);
			}

			return ret;
		}

		/// <summary>
		/// Gets the ele. 根据索引获取元素
		/// </summary>
		/// <returns>The ele.</returns>
		/// <param name="idx">Index.</param>
		public double getEle(int idx)
		{
			return arr[idx - 1];
		}

		/// <summary>
		/// Sets the ele. 根据索引设置元素
		/// </summary>
		/// <param name="idx">Index.</param>
		/// <param name="val">Value.</param>
		public void setEle(int idx, double val)
		{
			arr[idx - 1] = val;
		}

		public int EleCnt { get; set; }
		double[] arr;
	}

	/// <summary>
	/// CMatrix. 矩阵，索引从下标1开始，内存布局类似Matlab
	/// </summary>
	public class CMatrix
	{
		/// <summary>
		/// Initializes a new instance of the <see cref="T:CalcMatrix.CMatrix"/> class. 构造矩阵，传入行数、列数、和元素数组
		/// </summary>
		/// <param name="rowCnt">Row count.</param>
		/// <param name="colCnt">Col count.</param>
		/// <param name="arr">Arr.</param>
		public CMatrix(int rowCnt, int colCnt, double[] arr)
		{
			RowCnt = rowCnt;
			ColCnt = colCnt;
			this.arr = arr;

			rowList = new List<CVector>();
			colList = new List<CVector>();

			double[] rowArr = new double[ColCnt];
			for (int rowIdx = 1; rowIdx <= RowCnt; rowIdx++)
			{
				for (int colIdx = 1; colIdx <= ColCnt; colIdx++)
				{
					rowArr[colIdx - 1] = getEle(rowIdx, colIdx);
				}
				rowList.Add(new CVector(colCnt, rowArr));
			}
			double[] colArr = new double[RowCnt];
			for (int colIdx = 1; colIdx <= ColCnt; colIdx++)
			{
				for (int rowIdx = 1; rowIdx <= RowCnt; rowIdx++)
				{
					colArr[rowIdx - 1] = getEle(rowIdx, colIdx);
				}
				colList.Add(new CVector(RowCnt, colArr));
			}

			ThreadPool.SetMaxThreads(5, 5);
		}

		/// <summary>
		/// Arguments. 任务传入参数的集合结构
		/// </summary>
		class Args
		{
			public Args(int rowIdx, int colIdx, CVector row, CVector col, CMatrix ret)
			{
				this.rowIdx = rowIdx;
				this.colIdx = colIdx;
				this.row = row;
				this.col = col;
				this.ret = ret;
			}

			public int rowIdx;
			public int colIdx;
			public CVector row;
			public CVector col;
			public CMatrix ret;
		}

		/// <summary>
		/// Foo the specified obj. 线程任务
		/// </summary>
		/// <param name="obj">Object.</param>
		void foo(object obj)
		{
			Args args = obj as Args;
			args.ret.setEle(args.rowIdx, args.colIdx, args.row.multi(args.col).sum());
		}

		/// <summary>
		/// Multi the specified r. 矩阵乘法
		/// </summary>
		/// <param name="r">The red component.</param>
		public CMatrix multi(CMatrix r)
		{
			CMatrix ret = new CMatrix(RowCnt, r.ColCnt, new double[RowCnt * r.ColCnt]);
			List<Task> tasks = new List<Task>();
			for (int rowIdx = 1; rowIdx <= RowCnt; rowIdx++)
			{
				for (int colIdx = 1; colIdx <= r.ColCnt; colIdx++)
				{
					var task = Task.Factory.StartNew(new Action<object>(foo), new Args(rowIdx, colIdx, getRow(rowIdx), r.getCol(colIdx), ret));
					tasks.Add(task);
				}
			}

			Task.WaitAll(tasks.ToArray());

			return ret;
		}

		/// <summary>
		/// Gets the row. 根据行索引获取整行
		/// </summary>
		/// <returns>The row.</returns>
		/// <param name="rowIdx">Row index.</param>
		public CVector getRow(int rowIdx)
		{
			return rowList[rowIdx - 1];
		}

		/// <summary>
		/// Gets the col. 根据列索引获取整列
		/// </summary>
		/// <returns>The col.</returns>
		/// <param name="colIdx">Col index.</param>
		public CVector getCol(int colIdx)
		{
			return colList[colIdx - 1];
		}

		/// <summary>
		/// Gets the ele. 根据索引获取元素
		/// </summary>
		/// <returns>The ele.</returns>
		/// <param name="idx">Index.</param>
		public double getEle(int idx)
		{
			return arr[idx - 1];
		}

		/// <summary>
		/// Sets the ele. 根据索引设置元素
		/// </summary>
		/// <param name="idx">Index.</param>
		/// <param name="val">Value.</param>
		public void setEle(int idx, double val)
		{
			arr[idx - 1] = val;
		}

		/// <summary>
		/// Gets the ele. 根据行列索引获取元素
		/// </summary>
		/// <returns>The ele.</returns>
		/// <param name="rowIdx">Row index.</param>
		/// <param name="colIdx">Col index.</param>
		public double getEle(int rowIdx, int colIdx)
		{
			int idx = rowIdx + (colIdx - 1) * RowCnt;
			return getEle(idx);
		}

		/// <summary>
		/// Sets the ele. 根据行列索引设置元素
		/// </summary>
		/// <param name="rowIdx">Row index.</param>
		/// <param name="colIdx">Col index.</param>
		/// <param name="val">Value.</param>
		public void setEle(int rowIdx, int colIdx, double val)
		{
			int idx = rowIdx + (colIdx - 1) * RowCnt;
			setEle(idx, val);
		}

		public int RowCnt { get; set; }
		public int ColCnt { get; set; }
		double[] arr;
		List<CVector> rowList;
		List<CVector> colList;
	}
}

